package it.softphone.cmc.server.rest;

import it.softphone.cmc.server.service.QueryTask;
import it.softphone.cmc.server.service.exception.CMCException;
import it.softphone.cmc.server.service.exception.CMCMissingTenantException;
import it.softphone.cmc.shared.entity.Tenant;
import it.softphone.cmc.shared.security.Permissions;
import it.softphone.commons.json.server.JSONException;
import it.softphone.commons.json.server.jersey.JSONExceptionMapper;
import it.softphone.commons.json.server.jersey.JSONParam;

import java.util.Collections;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.apache.shiro.authz.annotation.RequiresPermissions;

import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;

/**
 * 
 * @author bsorrentino
 *
 */
@Path("/tenant")
public class CMCTenantManager extends RESTServiceAware  {

	/**
	 * 
	 * @author bsorrentino
	 *
	 */
	public static class  Result implements Tenant.ResultSet {

		java.util.List<Tenant> result ;
		
		@Override
		public List<Tenant> getResult() {
			return result;
		}

		@Override
		public void setResult(List<Tenant> result) {
			// MAKE A COPY
			this.result = new java.util.ArrayList<Tenant>( result );
		}
		
	}

	/**
	 * 
	 * @param method
	 * @param msg
	 * @param e
	 * @throws CMCRestException 
	 */
	protected void throwJSONException( String method, String msg, Exception e ) throws CMCRestException  {
		logger.error( String.format( "TenantManager[%s]: %s", method, msg ), e );
		
		throw new CMCRestException(Status.INTERNAL_SERVER_ERROR, e);
		
	}

	
	/////////////////////////////////////////////////////////////////////////////////
	///
	/// JSON AWARE
	///
	/////////////////////////////////////////////////////////////////////////////////
	
	
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	@Path("all")
	public it.softphone.commons.json.server.JSONObject getAllTenants() {
		
		final Result result = new Result();

		try {
			
			system().findAllTenants( new QueryTask<List<Tenant>>() {

				@Override
				public void run(List<Tenant> tenantList) throws Exception {
					
					
					if( tenantList==null ) {
						tenantList = Collections.emptyList();
					}
									
					result.setResult( tenantList);
			
				}
				
			});
				
			it.softphone.commons.json.server.JSONObject o = new it.softphone.commons.json.server.JSONObject( result );
			
			return o;
			
		} catch (CMCException e) {
			
			throw new JSONExceptionMapper(e);
		}
	}

	/**
	 * 
	 * @param name
	 * @param value
	 * @return
	 */
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public it.softphone.commons.json.server.JSONObject getTenant(	@QueryParam("id") String id,
											@QueryParam("value") @DefaultValue("") String value	) 
	{
		
		try {
			
			Tenant result = system().findTenantById(id, value);
			
			it.softphone.commons.json.server.JSONObject o = new it.softphone.commons.json.server.JSONObject( result );
			
			return o;
			
		} catch (CMCException e) {
			
			throw new JSONExceptionMapper(e);
		}
	}

	/**
	 * 
	 * @param tenant
	 * @return
	 */
	@POST
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	@Produces(MediaType.APPLICATION_JSON)
	@RequiresPermissions( Permissions.Tenant.CREATE )
	public it.softphone.commons.json.server.JSONObject createTenantFromJSon( @FormParam("item") JSONParam tenant ) throws CMCException 
	{
		final String method = "createTenantFromJSon";

		try {
			Tenant t = system().makeTenantFromJson(tenant.toObject());
			
			system().createTenant(t);

			return new it.softphone.commons.json.server.JSONObject(t);
			
			
		} catch (JSONException e) {
			throwJSONException( method, "converting JSON parameter", e);
			
		} catch (CMCMissingTenantException e) {
			throwJSONException( method, "missing tenant in parameter", e);
			
		} catch (Exception e) {
			throwJSONException( method, "error creating tenant", e);
		}		
	
		return null;
	}
	
	/**
	 * 
	 * @param tenant
	 * @return
	 */
	@PUT
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	@RequiresPermissions(  Permissions.Tenant.UPDATE )
	public it.softphone.commons.json.server.JSONObject updateTenantFromJSon( it.softphone.commons.json.server.JSONObject tenant ) throws CMCException 
	{
		final String method = "updateTenantFromJSon";
		
		try {
			
			logger.debug( method + "\n" + tenant.toString(4) );
			
			Tenant t = system().makeTenantFromJson(tenant);
			
			system().storeTenant(t);

			return new it.softphone.commons.json.server.JSONObject(t);
			
		} catch (JSONException e) {
			throwJSONException( method, "converting JSON parameter", e);
			
		} catch (CMCMissingTenantException e) {
			throwJSONException( method, "missing tenant in parameter", e);
			
		} catch (Exception e) {
			throwJSONException( method, "error creating tenant", e);
		}		
	
		return null;
	}

	/**
	 * 
	 * @param tenant
	 * @return
	 */
	@DELETE
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	@Produces({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON })
	@RequiresPermissions(  Permissions.Tenant.DELETE )
	public Response deleteTenantFromJSonV1( @FormParam("item") JSONParam tenant ) throws CMCException
	{
		final String method = "deleteTenantFromJSon";
		
		try {
			Tenant t = system().makeTenantFromJson(tenant.toObject());
			
			system().deleteTenant(t);

			return Response.ok().build();
			
		} catch (JSONException e) {
			throwJSONException( method, "converting JSON parameter", e);
			
		} catch (CMCMissingTenantException e) {
			throwJSONException( method, "missing tenant in parameter", e);
			
		} catch (Exception e) {
			throwJSONException( method, "error creating tenant", e);
		}
		
		return null;		
	
	}

	/**
	 * 
	 * @param tenant
	 * @return
	 */
	@DELETE
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON })
	@RequiresPermissions(  Permissions.Tenant.DELETE )
	public Response deleteTenantFromJSonV2( it.softphone.commons.json.server.JSONObject tenant ) throws CMCException
	{
		final String method = "deleteTenantFromJSon";
		
		try {
			Tenant t = system().makeTenantFromJson(tenant);
			
			system().deleteTenant(t);

		} catch (JSONException e) {
			throwJSONException( method, "converting JSON parameter", e);
			
		} catch (CMCMissingTenantException e) {
			throwJSONException( method, "missing tenant in parameter", e);
			
		} catch (Exception e) {
			throwJSONException( method, "error creating tenant", e);
		}
		return Response.ok().build();
		
	
	}

		
	/////////////////////////////////////////////////////////////////////////////////
	///
	/// LEGACY
	///
	/////////////////////////////////////////////////////////////////////////////////
	
/*	
	@GET
	@Produces("text/plain")
	public Response getTenantByAccount() {
		
		try {
			
			Account account = security().getPrincipal(Account.class);
			
			Tenant tenant = service().findTenantByName( account.getTenant() );
				
			return Response.ok().entity(JSONUtils.toJSON(tenant)).build();
		} catch (CMCException e) {
			return Response.status(Status.INTERNAL_SERVER_ERROR).entity(JSONUtils.toJSON(e)).build();
		}
	}
*/	
	
	@POST 
    @Produces("text/plain")
    @Consumes("multipart/form-data") 
	@RequiresPermissions(  Permissions.Tenant.CREATE )
	public Response createTenant(FormDataMultiPart part ) throws CMCException
	{
		FormDataBodyPart fieldLogo = part.getField("logo");
		FormDataBodyPart fieldName = part.getField("name");

		String name = fieldName.getValue();
		byte[] bytes = null;
		
		logger.debug( "fieldName " +  name);

		try {
			java.io.InputStream is = fieldLogo.getValueAs(java.io.InputStream.class);

			bytes = it.softphone.commons.util.Util.toBytes(is, 512);

			logger.debug( "fieldLogo " + bytes.length );
						
		}
		catch( Exception e ) {
			logger.error( "error get field as InputStream", e );
			
		}
	
		Tenant tenant = system().makeTenant();
		
		tenant.setName(name);
	
		if( bytes!=null && bytes.length>0 ) tenant.setLogoB( bytes );
		
		system().createTenant(tenant);
		
		return Response.ok("{ result:'success', type:'inserted'}").build();
		  
	}

	
	@PUT 
    @Produces(MediaType.TEXT_PLAIN)
    @Consumes( MediaType.MULTIPART_FORM_DATA)  
	@RequiresPermissions( Permissions.Tenant.UPDATE )
	public Response storeTenant(FormDataMultiPart part ) throws CMCException 
	{
		
		FormDataBodyPart fieldLogo = part.getField("logo");
		FormDataBodyPart fieldName = part.getField("name");

		String name = fieldName.getValue();
		byte[] bytes = null;
		
		logger.debug( String.format("name=[%s]", name));

		try {
			java.io.InputStream is = fieldLogo.getValueAs(java.io.InputStream.class);

			bytes = it.softphone.commons.util.Util.toBytes(is, 512);

			logger.debug( String.format("log byte length [%d] ", bytes.length ));
						
		}
		catch( Exception e ) {
			logger.error( "error get field as InputStream", e );
			
		}
			
		Tenant tenant = system().findTenantById( "name", name);
		
		if( bytes!=null && bytes.length>0 ) tenant.setLogoB(bytes);
		
		system().storeTenant(tenant);
		
		return Response.ok("{ result:'success', type:'updated'}").build();

	}

}
